iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
JavaScript

Signal API in Angular系列 第 11

Day 11 - explicitEffect - useEffect hook 的 Angular 版本

  • 分享至 

  • xImage
  •  

回顧第10天,effect追蹤signal並在任何signal值更新時運行effect函數。當signal不是effect的依賴項時,它會呼叫未追蹤的函數以防止訊號讀取。我對效果的主要挑戰是識別不應被視為效果函數依賴項的訊號。 當我發現ngXtension庫中的explicitEffect函數時,追蹤signal值得到了極大的簡化。 當dependency array中的signal發生變化時,explicitEffect函數才運行effect函數。

今天,我想用explicitEffect重寫第10天的effect例子。

安裝ngxtension

npm i ngxtension

從ngxtension中導入explicitEffect

import { explicitEffect } from 'ngxtension/explicit-effect';

發出HTTP請求並更新effect內的signal

  • 之前使用effect:
// character.component.ts

 effect((onCleanUp) => {
     const sub = getPersonMovies(this.id(), this.injector)
       .subscribe((result) => {
         if (result) {
           const [person, ...rest] = result;
           this.person.set(person);
           this.films.set(rest);
         } else {
           this.person.set(undefined);
           this.films.set([]);
         }
         this.rgb.set(generateRGBCode());
         this.rgb.set(generateRGBCode());
         this.rgb.set(generateRGBCode());
       });

     onCleanUp(() => sub.unsubscribe());
});
  • 使用explicitEffect後:
constructor() {
   explicitEffect([this.id], ([id], onCleanUp) => {
     const sub = getPersonMovies(id, this.injector)
       .subscribe((result) => {
         if (result) {
           const [person, ...rest] = result;
           this.person.set(person);
           this.films.set(rest);
         } else {
           this.person.set(undefined);
           this.films.set([]);
         }

         this.rgb.set(generateRGBCode());
         this.rgb.set(generateRGBCode());
         this.rgb.set(generateRGBCode());
       });

     onCleanUp(() => sub.unsubscribe());
   });
}

只有當dependency arrayid signal發生變更時,explicitEffect才會運作。 explicitEffect的第二個參數是執行explicitEffect邏輯的函數。 onCleanUp是一個explicitEffect清理函數,它在銷毀effect之前取消subscription

同步表單值

  • 之前使用effect:
untracked(() => {
   if (this.id() !== this.searchId()) {
      this.searchId.set(this.id());
   }
});

#logIDsEffect = effect(() => console.log('id ->', untracked(this.id), 'searchID ->', this.searchId()));
  • 使用explicitEffect後:
if (this.id() !== this.searchId()) {
   this.searchId.set(this.id());
}

explicitEffect不會明確追蹤searchId signal,因此不需要呼叫untracked函數來執行外部程式碼。

#logIDsEffect = explicitEffect([this.searchId], ([searchId]) => console.log('id ->', this.id(), 'searchID ->', searchId), 
{ defer: true });

我創建了一個新的explicitEffect來追蹤dependency array中的searchId signal。 explicitEffect函數記錄idsearchId的值。 新增第三個參數{ defer: rue }以延遲effect,直到searchId發生變更。

searchId = signal(initialId);

首次初始化searchId signal時沒有日誌訊息。

if (this.id() !== this.searchId()) {
   this.searchId.set(this.id());
}
<input type="number" [(ngModel)]="searchId" name="searchId" id="searchId" />

searchId signal變更時,將記錄該訊息。

更新host element的CSS變數

  • 之前使用effect:
this.renderer.setProperty(this.hostElement, 'style', `--main-font-size: ${untracked(this.fontSize)}`);
#rgbEffect = effect(() => console.log('rgb ->', this.rgb()));
  • 使用explicitEffect後:
this.renderer.setProperty(this.hostElement, 'style', `--main-font-size: ${this.fontSize()}`);

explicitEffect不會明確追蹤fontSize signal,因此,它不需要呼叫untracked函數來取得值。

#rgbEffect = explicitEffect([this.rgb], ([rgb]) => console.log('rgb ->', rgb), { defer: true });

我創建了一個新的explicitEffect來追蹤dependency arrayrgb signal。 explicitEffect 函數記錄rgb值。 新增第三個參數{ defer: rue }以延遲effect,直到rgb發生變更。

rgb = signal('brown');

首次初始化rgb signal時沒有日誌訊息。

const sub = getPersonMovies(id, this.injector)
   .subscribe((result) => {
       this.rgb.set(generateRGBCode());
       this.rgb.set(generateRGBCode());
       this.rgb.set(generateRGBCode());
   });

設定rgb signal後,將記錄該訊息。

鐵人賽第11天就這樣結束了。

參考:


上一篇
Day 10 - Signal API - 我們可以在Effect中做什麼?
下一篇
Day 12 - 介紹 Signal Input
系列文
Signal API in Angular39
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言